﻿
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.Reflection;
using System.Xaml;

namespace SL8.SL.Markups
{
    public class Static : DependencyObject, IMarkupExtension<Object>
    {
        private String _member;
        private Type _memberType;
        public Static()
        {
        }

        public Object ProvideValue(IServiceProvider serviceProvider)
        {
            Object ret = null;
            Boolean typeResolveFailed = true;
            Type type = MemberType;
            String fieldMemberName = null;
            String fullFieldMemberName = null;

            if (Member != null)
            {
                if (MemberType != null)
                {
                    fieldMemberName = Member;
                    fullFieldMemberName = String.Format("{0}.{1}", type.FullName, Member);
                }
                else
                {
                    //on a pas le type, on regarde si la chaine est bien formatée ex : local:MyEnum.MyEnumeValue et on essaie de résoudre le type
                    Int32 index = Member.IndexOf('.');

                    if (index >= 0)
                    {
                        string typeName = Member.Substring(0, index);

                        if (!String.IsNullOrEmpty(typeName))
                        {
                            IXamlTypeResolver xamlTypeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
                            IProvideValueTarget ot = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

                            IRootObjectProvider rootObjectProvider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;

                            object obj = ot.TargetObject;
                            var v = ot.TargetProperty;

                            if (xamlTypeResolver != null)
                            {
                                type = xamlTypeResolver.Resolve(typeName);
                                fieldMemberName = Member.Substring(index + 1); //, Member.Length - index - 1
                                typeResolveFailed = String.IsNullOrEmpty(fieldMemberName);
                            }
                        }
                    }
                }

                if (typeResolveFailed)
                {
                    throw new InvalidOperationException("Member");
                }
                else
                {
                    if (type.IsEnum) //si c'est un enum alors on essaie de résoudre le membre
                    {
                        ret = Enum.Parse(type, fieldMemberName, true);
                    }
                    else //ce n'est pas un enum : probablement un champ ou une propriété
                    {
                        Boolean fail = true;
                        FieldInfo field = type.GetField(fieldMemberName, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static);

                        if (field != null)
                        {
                            fail = false;
                            ret = field.GetValue(null);
                        }
                        else//ce n'est pas un champ, on regarde si c'est une propriété
                        {
                            //on regarde si c'est une propriété
                            PropertyInfo property = type.GetProperty(fieldMemberName, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static);

                            if (property != null)//c'est une propriété
                            {
                                fail = false;
                                ret = property.GetValue(null, null);
                            }
                        }

                        if (fail)
                        {
                            throw new ArgumentException(fullFieldMemberName);
                        }
                    }
                }
            }
            else
            {
                throw new InvalidOperationException();
            }

            return ret;
        }

        #region Membres
        /// <summary>
        /// Obtient ou définit le membre statique à résoudre ex : local:MyEnum.MyEnumValue si pas de MemberType sinon MyEnumValue
        /// </summary>
        public string Member
        {
            get
            {
                return _member;
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("Member value");
                }

                _member = value;
            }

        }

        /// <summary>
        /// Obtient ou définit le type du membre à résoudre
        /// </summary>
        public Type MemberType
        {
            get
            {
                return _memberType;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("MemberType value");
                }
                _memberType = value;
            }
        }

        #endregion
    }
}
